package casepattern

/**
  * 模式匹配
  * 格式： 选择器 match {可选分支}
  * 每个分支包括一个模式以及一个或者多个表达式
  * 与java switch对比
  * 1.scala的match是一个表达式，也就是说总能得到一个值
  * 2.scala的可选分支不会贯穿到下一个case
  * 3.如果没有一个模式匹配上，会抛出MatchError
  */
class Patterns {
  /**
    * 通配模式，使用_匹配任何对象，也可以用来忽略某个对象不关心的部分
    * 例如case BinOp(op, left, right) 也可以写成case BinOp(_, _, right)
    *
    * @param expr
    */
  def doGeneralMatch(expr: Expr): Unit = {
    expr match {
      case BinOp(op, left, right) =>
        println("This is a BinOp")
      case _ =>
        println("default")
    }

    /**
      * 常量模式：常量模式仅匹配自己，任何字面量都可以作为常量使用，
      * 任何val或单例对象也可以作为常量模式使用
      *
      * @param x
      */
    def doConstMatch(x: Any): Unit = {
      x match {
        case 5 => print("5")
        case true => print("true")
        case "hello" => println("hello")
        case Nil => println("empty list")
        case _ => println("something else")
      }
    }

    /**
      * 变量模式：匹配任何对象，与通用模式不同的是，会将对象绑定到变量上
      *
      * @param x
      */
    def doVariableMatch(x: Any): Unit = {
      x match {
        case 0 => println("zero")
        case other => print("other is " + other)
      }
    }

    /**
      * 构造方法匹配：支持深度匹配，不仅会检查给出的对象的顶层，还会进一步检查对象的内容是否匹配
      *
      * @param expr
      */
    def doConstructorMatch(expr: Expr): Unit = {
      expr match {
        // 不仅匹配对象类型为BinOp，还会匹配字段为“+”和Number(0)
        case BinOp("+", e, Number(0)) => println("a deep match")
        case _ =>
      }
    }

    /**
      * 序列匹配
      *
      * @param x
      */
    def doSequenceMatch(x: List[Int]): Unit = {
      x match {
        // 匹配以0开头的三个元素的list
        case List(0, _, _) => println("List(0,_,_)")
        //匹配以1开头的至少一个元素的list
        case List(1, _*) => println("List(1,_*)")
        case _ =>
      }
    }

    /**
      * 元祖匹配
      *
      * @param x
      */
    def doTupleMatch(x: Any): Unit = {
      x match {
        case (a, b, c) => println("(a,b,c)")
        case _ =>
      }
    }

    /**
      * 类型匹配
      * @param x
      */
    def doTypeMatch(x: Any): Unit = {
      x match {
        case s: String => println("String")
        case m: Map[_, _] => println("map")
        case _ =>
      }
    }
  }

}
